#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "comm/ota.h"
#include "firmware.h"
#include "public/errno.h"
#include "bsp_uart.h"
#include "bsp.h"
#include "flash_main.h"
#include "elog.h"
#include "ota_ware.h"
#include "aadl/public.h"
#include "aadl/include/aadl/flash.h"

#define IOT_TYPE    6           //IOT固件类型，对应AT+OTASTR中的类型
#define IOT_SIZE    496*1024    //IOT固件大小，固件最大大小
#define IOT_SAVE    1           //0：表示保存到内存，数据掉电丢失；1：表示保存到外部FLASH，数据掉电任然存在
#define IOT_ADDR    0x00001000  //数据保存地址，保存外部FLASH起始地址，包含64字节头部信息

static int check(unsigned int type, unsigned int size, unsigned int save, unsigned int addr);
static int update(unsigned int type, unsigned int size, unsigned int save, unsigned int addr);


static int check(unsigned int type, unsigned int size, unsigned int save, unsigned int addr)
{
    firmware_head_t head = {0};
    if (save == 0) {
        /* 从SDRAM中读取固件头 */
        memcpy(&head, (void *)addr, sizeof(firmware_head_t));
    }
    else {
        /* 从flash中读取固件头 */
        app_flash_read(sizeof(firmware_head_t), (uint8_t *)&head, 0);
    }

    /* 检查固件标记 */
    if (0 != memcmp(head.flag, FIRMWARE_FLAG_STR, strlen(FIRMWARE_FLAG_STR))) {
        return -EBFONT;
    }

    /* 检查固件类型*/
    if (head.file_type != FIRMWARE_TYPE_IOT) {
         return -EBADFD;
    }

    return 0;
}


static int update(unsigned int type, unsigned int size, unsigned int save, unsigned int addr)
{
    /* 重启之前，应答升级成功 */
    int ret = 0;
    
    log_i("update ready, write ota ready flag to first sector!\r\n");

    /* 延时等待发送完成 */
    unsigned int timestart = getms();
    while (getms() > timestart + 100) {}

    /* 重启之前，设置boot状态标记 */
    char bootinfo_str[16] = "REDY";
    ret = aad_flash_direct_write(FILE_OTA_FLAG_ID, 0, (uint8_t *)bootinfo_str, strlen(bootinfo_str), AADL_WAIT | AADL_KEEP_OUTSIDE , 0);
    if (ret != 0) {
        ret = aad_flash_direct_write(FILE_OTA_FLAG_ID, 0, (uint8_t *)bootinfo_str, strlen(bootinfo_str), AADL_WAIT | AADL_KEEP_OUTSIDE , 0);
        log_i("Fail to set ota flag id, reason: %d", ret);

        return ret;
    }
    
    return 0;
}

ota_firmware_xfa_t ota_firmware_iot_xfa = {
    .type = IOT_TYPE,
    .size = IOT_SIZE,
    .save = IOT_SAVE,
    .addr = IOT_ADDR,
    .check = check,
    .update = update,
};OTA_WARE_REGISTER(IOT_TYPE, IOT_SIZE, IOT_SAVE, IOT_ADDR, check, update);

